home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1997 March / macformat-048.iso / Shareware Plus / Updaters / NewsWatcher 2.15+jp1 folder / patch source CW10 / myMime.c next >
Encoding:
Text File  |  1996-12-16  |  14.1 KB  |  600 lines  |  [TEXT/CWIE]

  1. // ==================================================
  2. //    myMime.c
  3. //    Copyright (C) 1996 Mizutori Tetsuya, August 20, 1996, October 7, 1996.
  4. // ==================================================
  5. //    This document is pretty-printed in 10-point Geneva font.
  6.  
  7. #include "myMime.h"
  8.  
  9. #ifdef DEBUG
  10. // This debug routine requires a dialog resource of 'DITL' and 'ALRT' whose ID is 1000.
  11. #define    kAlertID        1000
  12. #define    kNilFilterProc    nil
  13. void SignalMsg( const unsigned char *p, const unsigned long pLen, Str255 msg );
  14. void SignalMsg( const unsigned char *p, const unsigned long pLen, Str255 msg )
  15. {
  16.     short        item;
  17.     Str31    errNumbStr;
  18.     Str255    str;
  19.  
  20.     str[0] = pLen;
  21.     BlockMoveData(p,&str[1],str[0]);
  22.  
  23.     NumToString( pLen, errNumbStr );
  24.  
  25.     ParamText( errNumbStr, msg, str, "\p" );
  26.  
  27.     item = NoteAlert( kAlertID, kNilFilterProc );
  28.     if ( item == cancel ) ExitToShell();
  29. }
  30. #endif // DEBUG
  31.  
  32.  
  33. // constants and global variables
  34. const unsigned char        kPadChar                 = '=';
  35.  
  36. const unsigned char        kMimeBeginMark[]         = "=?";
  37. const unsigned long        kMimeBeginMarkLen         = 2;
  38. const unsigned char        kMimeEndMark[]         = "?=";
  39. const unsigned long        kMimeEndMarkLen         = 2;
  40. const unsigned char        kMimeSeparator[]         = "?";
  41. const unsigned long        kMimeSeparatorLen         = 1;
  42. const unsigned char        kCharSetName[]             = "iso-2022-jp";
  43. const unsigned long        kCharSetNameLen         = 11;
  44. const unsigned char        kEncodingName[]         = "B";
  45. const unsigned long        kEncodingNameLen         = 1;
  46.  
  47.  
  48. // --------------------------------------------------
  49. //        • CalcMimeEncodeLength
  50. // --------------------------------------------------
  51. // Mime separators and deliminators
  52.  
  53. #ifdef MIME_ENCODE
  54. static unsigned long
  55. CalcMimeEncodeLength(
  56.     unsigned long    textSize )
  57. {
  58.     unsigned long    theSize;
  59.  
  60.     theSize = ( (textSize - 1)/3 + 1) * 4;    /* Body */
  61.  
  62.     theSize += kMimeBeginMarkLen + kCharSetNameLen + kMimeSeparatorLen +
  63.              kEncodingNameLen + kMimeSeparatorLen + /* Body + */ kMimeEndMarkLen;
  64.  
  65.     return theSize;
  66. }
  67. #endif // MIME_ENCODE
  68.  
  69.  
  70. // ==================================================
  71. //    Mime encoding
  72. // ==================================================
  73.  
  74. #ifdef MIME_ENCODE
  75.  
  76. #ifdef MIME_ENCODE
  77. static const unsigned char        Base64[ 64+4 ] = 
  78.     "ABCDEFGHIJKLMNOP"
  79.     "QRSTUVWXYZabcdef"
  80.     "ghijklmnopqrstuv"
  81.     "wxyz0123456789+/"
  82.     ;
  83. #endif // MIME_ENCODE
  84.  
  85.  
  86. // --------------------------------------------------
  87. //        • MimeEncode
  88. // --------------------------------------------------
  89.  
  90. void
  91. MimeEncode(
  92.     Handle        textH,
  93.     unsigned long *    textSizeP )
  94. {
  95.     unsigned long    textSize = *textSizeP;
  96.     unsigned long    newSize = CalcMimeEncodeLength( textSize );
  97.  
  98.     // Add extra spaces to 'textH', which enables to store the resulted text.
  99.     SetHandleSize( textH, newSize );
  100.     if ( MemError() != noErr ) return;
  101.  
  102.     {
  103.     unsigned char *    textP = (unsigned char *) *textH;
  104.     BlockMoveData( textP, textP+(newSize-textSize), textSize );
  105.  
  106. //    HLock( textH );
  107.     MimeEncodeText( textP+(newSize-textSize), textSize, textP, &newSize );
  108. //      HUnlock( textH );
  109.     }
  110.  
  111.     // Resize the resulted 'textH'.
  112.     *textSizeP = newSize;
  113.     SetHandleSize( textH, newSize );
  114. }
  115. #endif // MIME_ENCODE
  116.  
  117.  
  118. #ifdef MIME_ENCODE
  119. // --------------------------------------------------
  120. //        • MimeEncodeJIS
  121. // --------------------------------------------------
  122.  
  123. const unsigned char        kEscKanjiIn[]            = "\033$";
  124. const unsigned long        kEscKanjiInLen            = 2;
  125. const unsigned char        kEscKanjiOut[]            = "\033(";
  126. const unsigned long        kEscKanjiOutLen            = 2;
  127. const unsigned char        kEscKanjiInx[]            = "B@";
  128. const unsigned long        kEscKanjiInxLen            = 2;
  129. const unsigned char        kEscKanjiOutx[]            = "JBH";
  130. const unsigned long        kEscKanjiOutxLen        = 3;
  131.  
  132. void
  133. MimeEncodeJIS(
  134.     Handle        textH,
  135.     unsigned long *    textSize )
  136. {
  137.     unsigned long    theSize;
  138.     Handle        theHndl;
  139.  
  140.     unsigned char *    p = (unsigned char *) *textH;
  141.     unsigned char *    pEnd = p+ *textSize;
  142.  
  143.     unsigned char *    pLast = p;
  144.     unsigned char *    pKanjiStart = nil;
  145.  
  146.     unsigned long    len;
  147.  
  148.     HLock( textH );
  149.  
  150.     theSize = 0;
  151.     theHndl = NewHandleClear( theSize );
  152.     if ( MemError() != noErr ) return;
  153.  
  154.     while ( p < pEnd ) {
  155.  
  156.         if ( IsSameString(p,kEscKanjiInLen,kEscKanjiIn,kEscKanjiInLen) &&
  157.             FindToken( kEscKanjiInx, kEscKanjiInxLen, p+kEscKanjiInLen, 1, &len ) ) {
  158.  
  159.             pKanjiStart = p;
  160.             p += kEscKanjiInLen + 1;
  161.  
  162.         } else 
  163.         if ( IsSameString(p,kEscKanjiOutLen,kEscKanjiOut,kEscKanjiOutLen) &&
  164.             FindToken( kEscKanjiOutx, kEscKanjiOutxLen, p+kEscKanjiOutLen, 1, &len ) &&
  165.             pKanjiStart != nil ) {
  166.  
  167.             // Copy [pLast,pKanjiStart-1] -> q+
  168.             TextAppend( theHndl, &theSize, pLast, pKanjiStart );
  169.             {
  170.             // MimiCode [pKanjiStart+3,p-1] -> q+
  171.             unsigned char *    theBodyStart = pKanjiStart;
  172.             unsigned long    theBodySize = p - theBodyStart + kEscKanjiOutLen + 1;
  173.             unsigned long    theMimeSize = CalcMimeEncodeLength(theBodySize);
  174.             unsigned char *    theMimeP = (unsigned char *) NewPtrClear( theMimeSize );
  175.             MimeEncodeText( theBodyStart, theBodySize, theMimeP, &theMimeSize );
  176.             TextAppend( theHndl, &theSize, theMimeP, theMimeP+theMimeSize );
  177.             }
  178.             // p += 3; // pLast = p; // pKanjiStart = nil;
  179.             p += kEscKanjiOutLen + 1;
  180.             pLast = p;
  181.             pKanjiStart = nil;
  182.  
  183.     } else {
  184.  
  185.             p++;
  186.  
  187.         }
  188.     }
  189.  
  190.     // Copy [pLast,pEnd-1] -> q+
  191.     TextAppend( theHndl, &theSize, pLast, pEnd );
  192.  
  193.     HUnlock( textH );
  194.  
  195.     {
  196.     unsigned char *        theTextP = (unsigned char *) *theHndl;
  197.     HLock( theHndl );
  198.     *textSize = 0;
  199.     TextAppend( textH, textSize, theTextP, theTextP+theSize );
  200.     HUnlock( theHndl );
  201.     }
  202.  
  203.   out:
  204.     DisposeHandle( theHndl );
  205. }
  206. #endif // MIME_ENCODE
  207.  
  208.  
  209. #ifdef MIME_ENCODE
  210. // --------------------------------------------------
  211. //        • MimeEncodeText
  212. // --------------------------------------------------
  213.  
  214. unsigned long
  215. MimeEncodeText(
  216.     const unsigned char *    pStart,
  217.     const unsigned long    pLen,
  218.     unsigned char *        qStart,
  219.     unsigned long *        qLen )
  220. {
  221.     unsigned char *    q = qStart;
  222.  
  223.     BlockMoveData( kMimeBeginMark, q, kMimeBeginMarkLen );
  224.     q += kMimeBeginMarkLen;
  225.     BlockMoveData( kCharSetName, q, kCharSetNameLen );
  226.     q += kCharSetNameLen;
  227.     BlockMoveData( kMimeSeparator, q, kMimeSeparatorLen );
  228.     q += kMimeSeparatorLen;
  229.     BlockMoveData( kEncodingName, q, kEncodingNameLen );
  230.     q += kMimeSeparatorLen;
  231.     BlockMoveData( kMimeSeparator, q, kMimeSeparatorLen );
  232.     q += kMimeSeparatorLen;
  233.  
  234.     {
  235.     unsigned long    len;
  236.     Base64EncodeBody( pStart, pLen, q, &len );
  237.     q += len;
  238.     }
  239.  
  240.     BlockMoveData( kMimeEndMark, q, kMimeEndMarkLen );
  241.     q += kMimeEndMarkLen;
  242.  
  243.     *qLen = (unsigned long) ( q - qStart );
  244.  
  245.     return pLen;
  246. }
  247. #endif // MIME_ENCODE
  248.  
  249.  
  250. #ifdef MIME_ENCODE
  251. // --------------------------------------------------
  252. //        • Base64EncodeBody
  253. // --------------------------------------------------
  254.  
  255. static void
  256. Base64EncodeBody(
  257.     const unsigned char *    p,
  258.     const unsigned long    pLen,
  259.     unsigned char *        q,
  260.     unsigned long *        qLen )
  261. {
  262.     const unsigned char *    pEnd = p + pLen;
  263.     unsigned char *        qStart = q;
  264.  
  265.     unsigned char        s[4];
  266.     unsigned long        i, n;
  267.     while ( p < pEnd ) {
  268.         i = 0;
  269.         while ( i < 3 && p < pEnd ) s[i++] = *p++;
  270.         Base64Encode324( s, i, q, &n );
  271.         q += n;
  272.     }
  273.  
  274.     *qLen = (unsigned long) (q - qStart);
  275. }
  276. #endif // MIME_ENCODE
  277.  
  278.  
  279. #ifdef MIME_ENCODE
  280. // --------------------------------------------------
  281. //        • Base64Encode324
  282. // --------------------------------------------------
  283.  
  284. static void
  285. Base64Encode324(
  286.     const unsigned char *    p3,
  287.     const unsigned long    pLen,        // in: pLen = [1,2,3]
  288.     unsigned char *        q4,
  289.     unsigned long *        qLen )    // out: qLen = 4
  290. {
  291.     long    i;
  292.     long    n = 0;
  293.     BlockMoveData( p3, (unsigned char *) &n, pLen );
  294.  
  295.     for ( /*long*/ i=0; i<=pLen; i++ ) {
  296.         unsigned char    c = (n>>(26-6*i)) & 0x3F;
  297.         q4[i] = Base64[ c ];
  298.     }
  299.  
  300.     for ( /*long*/ i=pLen+1; i<4; i++ )
  301.         q4[i] = kPadChar;
  302.  
  303.     *qLen = 4;
  304. }
  305. #endif // MIME_ENCODE
  306.  
  307.  
  308. // ==================================================
  309. //    Mime decoding
  310. // ==================================================
  311.  
  312. #ifdef MIME_DECODE
  313. static const unsigned char        Esab64[ 128 ] = {
  314.     // 0x00-0x1F
  315.     0,0,0,0,0,0,0,0,            0,0,0,0,0,0,0,0,
  316.     0,0,0,0,0,0,0,0,            0,0,0,0,0,0,0,0,
  317.     //  !"#$%&'()*+,-./
  318.     0,0,0,0,0,0,0,0,            0,0,0,62,0,0,0,63,
  319.     // 0123456789:;<=>?
  320.     52,53,54,55,56,57,58,59,    60,61,0,0,0,0,0,0,
  321.     // @A-O
  322.     0,0,1,2,3,4,5,6,            7,8,9,10,11,12,13,14,
  323.     // P-Z[\]^_
  324.     15,16,17,18,19,20,21,22,    23,24,25,0,0,0,0,0,
  325.     // `a-o
  326.     0,26,27,28,29,30,31,32,        33,34,35,36,37,38,39,40,
  327.     // p-z{|}~\0
  328.     41,42,43,44,45,46,47,48,    49,50,51,0,0,0,0,0,
  329.     };
  330. #endif // MIME_DECODE
  331.  
  332.  
  333. #ifdef MIME_DECODE
  334. // --------------------------------------------------
  335. //        • MimeDecode
  336. // --------------------------------------------------
  337.  
  338. void
  339. MimeDecode(
  340.     Handle            textH,
  341.     unsigned long *        textSize )
  342. {
  343.     unsigned char *        pStart = (unsigned char *) *textH;
  344.     unsigned char *        pEnd = pStart + *textSize;
  345.     unsigned char *        p = pStart;
  346.     unsigned char *        q = pStart;
  347.     unsigned long        qLen;
  348.  
  349.     while ( p < pEnd ) {
  350.  
  351.         unsigned long    len;
  352.         if ( *p == kMimeBeginMark[0] &&
  353.             ( len = MimeDecodeText( p, (unsigned long) (pEnd - p), q, &qLen ) ) > 0 ) {
  354.             p += len;
  355.             q += qLen;
  356.         } else {
  357.             *q++ = *p++;
  358.         }
  359.     }
  360.  
  361.     // Resize the 'textH'.
  362.     *textSize =  (unsigned long) ( q - pStart );
  363.     SetHandleSize( textH, *textSize );
  364. //    ThrowIfOSErr_( ::MemError() );
  365. }
  366. #endif // MIME_DECODE
  367.  
  368.  
  369. #ifdef MIME_DECODE
  370. // --------------------------------------------------
  371. //        • MimeDecodeText
  372. // --------------------------------------------------
  373. //    p[] = "=?iso-2022-jp?B?xxxxxxxx?=AAAAAA..."
  374. //    ->
  375. //    p[return] = "AAAAAA..."
  376. //    q[] = "yyyyyy"
  377.  
  378. unsigned long
  379. MimeDecodeText(
  380.     const unsigned char *    pStart,
  381.     const unsigned long    pLen,
  382.     unsigned char *        qStart,
  383.     unsigned long *        qLen )
  384. {
  385.     const unsigned char *        pEnd = pStart + pLen;
  386.     const unsigned char *        p = pStart;
  387.     unsigned char *            q = qStart;
  388.     unsigned long            len;
  389.  
  390.     *qLen = 0;
  391.  
  392.     // The text must begin with 'kMimeBeginMark'.
  393.     if ( ! FindToken( p, (pEnd-p), kMimeBeginMark, kMimeBeginMarkLen, &len ) ||
  394.         len != 0 ) return 0;
  395.     p += kMimeBeginMarkLen;
  396.  
  397.     // Check 'kCharSetName'.
  398.     if ( ! FindToken( p, (pEnd-p), kMimeSeparator, kMimeSeparatorLen, &len ) ||
  399.         ! IsSameString( p, len, kCharSetName, kCharSetNameLen ) ) return 0;
  400.     p += len + kMimeSeparatorLen;
  401.  
  402.     // Check 'kEncodingName'.
  403.     if ( ! FindToken( p, (pEnd-p), kMimeSeparator, kMimeSeparatorLen, &len ) ||
  404.         ! IsSameString( p, len, kEncodingName, kEncodingNameLen ) ) return 0;
  405.     p += len + kMimeSeparatorLen;
  406.  
  407.     // Pick up the encoded body.
  408.     {
  409.     const unsigned char *    theEncodeBodyP = p;
  410.     unsigned long        theEncodeBodyLen;
  411.     if ( ! FindToken( p, (pEnd-p), kMimeEndMark, kMimeEndMarkLen, &theEncodeBodyLen ) ) return 0;
  412.     p += theEncodeBodyLen + kMimeEndMarkLen;
  413.  
  414.     Base64DecodeBody( theEncodeBodyP, theEncodeBodyLen, q, &len );
  415.     *qLen += len;
  416.     }
  417.  
  418.     return (unsigned long) (p - pStart);
  419. }
  420. #endif // MIME_DECODE
  421.  
  422.  
  423. #ifdef MIME_DECODE
  424. // --------------------------------------------------
  425. //        • Base64DecodeBody
  426. // --------------------------------------------------
  427.  
  428. static void
  429. Base64DecodeBody(
  430.     const unsigned char *    p,
  431.     const unsigned long    pLen,
  432.     unsigned char *        q,
  433.     unsigned long *        qLen )
  434. {
  435.     const unsigned char *    pEnd = p + pLen;
  436.     unsigned char *        qStart = q;
  437.  
  438.     unsigned char        s[4];
  439.     unsigned long        i, n;
  440.     while ( p < pEnd ) {
  441.         i = 0;
  442.         while ( i < 4 && p < pEnd ) {
  443.             while ( p < pEnd ) {
  444.                 if ( IsCharBase64( *p ) ) { s[i++] = *p++; break; }
  445.                 ++p;
  446.             }
  447.         }
  448.         Base64Decode423( s, i, q, &n );
  449.         q += n;
  450.     }
  451.  
  452.     *qLen = (unsigned long) (q - qStart);
  453. }
  454. #endif // MIME_DECODE
  455.  
  456. #ifdef MIME_DECODE
  457. // --------------------------------------------------
  458. //        • Base64Decode423
  459. // --------------------------------------------------
  460.  
  461. static void
  462. Base64Decode423(
  463.     const unsigned char *    p4,
  464.     const unsigned long    pLen,        // in: pLen = 4
  465.     unsigned char *        q3,
  466.     unsigned long *        qLen )    // out: qLen = [1,2,3]
  467. {
  468.     long    i;
  469.     long    n = 0;
  470.     long    k = 3;
  471.  
  472.     for ( /*long*/ i=0; i<4; i++ ) {
  473.         unsigned char    c = ( i < pLen ? p4[i] : kPadChar );
  474.         n = (n<<6) + Esab64[ c & 0x7F ];
  475.         if ( c == kPadChar ) k--;
  476.     }
  477.     n <<= 8;
  478.  
  479.     BlockMoveData( (unsigned char *) &n, q3, k );
  480.     *qLen = k;
  481. }
  482. #endif // MIME_DECODE
  483.  
  484.  
  485. // ==================================================
  486. //    Common functions
  487. // ==================================================
  488.  
  489. static const unsigned char    xlat[128] = 
  490.     // 0x00-0x1F
  491.     "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017"
  492.     "\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
  493.     " !\"#$%&'()*+,-./"
  494.     "0123456789:;<=>?"
  495.     "@ABCDEFGHIJKLMNO"
  496.     "PQRSTUVWXYZ[\\]^_"
  497.     "`ABCDEFGHIJKLMNO"            //    Replacing "`abcdefghijklmno".
  498.     "PQRSTUVWXYZ{|}~"            //    Replacing "pqrstuvwxyz{|}~\0".
  499.     ;
  500.  
  501. // --------------------------------------------------
  502. //        • IsCharBase64
  503. // --------------------------------------------------
  504.  
  505. static Boolean
  506. IsCharBase64(
  507.     unsigned char    theChar )
  508. {
  509.     if ( 'A' <= theChar && theChar  <= 'Z' ) return true;
  510.     if ( 'a' <= theChar && theChar <= 'z' ) return true;
  511.     if ( '0' <= theChar && theChar <= '9' ) return true;
  512.     if ( theChar == '+' ) return true;
  513.     if ( theChar == '/' ) return true;
  514.     if ( theChar == kPadChar ) return true;
  515.  
  516.     return false;
  517. }
  518.  
  519.  
  520. // --------------------------------------------------
  521. //        • FindToken
  522. // --------------------------------------------------
  523.  
  524. static Boolean
  525. FindToken(
  526.     const unsigned char *        pStart,
  527.     const unsigned long        pLen,
  528.     const unsigned char *        token,
  529.     const unsigned long        tokenLen,
  530.     unsigned long *            index )
  531. {
  532.     unsigned long    i = 0;
  533.     unsigned char    c = xlat[ token[0] & 0x7F ];
  534.  
  535.     while ( i < pLen ) {
  536.         if ( ( xlat[ pStart[i] & 0x7F ] == c ) && ( i+tokenLen <= pLen ) && 
  537.             IsSameString( &pStart[i], tokenLen, token, tokenLen ) ) {
  538.                 *index = i;
  539.                 return true;
  540.         }
  541.         i++;
  542.     }
  543.  
  544.     *index = 0;
  545.     return false;
  546. }
  547.  
  548.  
  549. // --------------------------------------------------
  550. //        • IsSameString
  551. // --------------------------------------------------
  552.  
  553. static Boolean
  554. IsSameString(
  555.     const unsigned char *        strA,
  556.     const unsigned long        strALen,
  557.     const unsigned char *        strB,
  558.     const unsigned long        strBLen )
  559. {
  560.     unsigned long        i = 0;
  561.  
  562.     while ( i<strALen && i<strBLen ) {
  563.         if ( xlat[ strA[i] & 0x7F ] != xlat[ strB[i] & 0x7F ] ) return false;
  564.         i++;
  565.     }
  566.  
  567.     return ( strALen == strBLen );
  568. }
  569.  
  570.  
  571. #ifdef MIME_ENCODE
  572. // --------------------------------------------------
  573. //        • TextAppend
  574. // --------------------------------------------------
  575.  
  576. static unsigned long
  577. TextAppend(
  578.     Handle            textH,
  579.     unsigned long *        textSize,
  580.     unsigned char *        pStart,
  581.     unsigned char *        pEnd )
  582. {
  583.     unsigned long    theLen = (unsigned long) ( pEnd - pStart );
  584.     unsigned long    theSize = *textSize;
  585.  
  586.     if ( theLen == 0 ) goto out;
  587.  
  588.     SetHandleSize( textH, theSize+theLen );
  589.     if ( MemError() != noErr )  goto out;
  590.  
  591.     BlockMoveData( pStart, ((unsigned char *) *textH)+theSize, theLen );
  592.     *textSize = theSize+theLen;
  593.  
  594.   out:
  595.     return theLen;
  596. }
  597. #endif // MIME_ENCODE
  598.  
  599. // end of program
  600.